﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Input;

namespace PonGun
{
    public class Bat : Base2DObject
    {
        int XClamp { get; set; }
        public PlayerIndex Player { get; set; }

        public float Speed { get; set; }

        public override Vector2 minPosition { get { return new Vector2(XClamp, Game1.RenderArea.Top + halfHeight + Game1.ScreenMargin); } }
        public override Vector2 maxPosition { get { return new Vector2(XClamp, Game1.RenderArea.Bottom - halfHeight - Game1.ScreenMargin); } }

        public List<BatGun> Guns = new List<BatGun>();

        public int rndTimeOffset;

        public int Score;

        public Bat(Game1 game, PlayerIndex player)
            : base(game)
        {
            Score = 0;

            Width = 8;
            Height = 64;

            Player = player;
            
            Asset = "Textures/Bats/bat1";

            rndTimeOffset = (int)(1000 * uniqueRND);

            switch (Player)
            {
                case PlayerIndex.One:
                    //Color = Game1.Player1Color;
                    XClamp = Game1.RenderArea.Width - (128 + Game1.ScreenMargin);
                    //Guns.Add(new BatGun(Game, this, "Textures/BatGun/TopRBasic", GunPos.Top) { rateOfFire = new TimeSpan(0, 0, 0, 1, rndTimeOffset + 50) });
                    //Guns.Add(new BatGun(Game, this, "Textures/BatGun/MidRBasic", GunPos.Center) { rateOfFire = new TimeSpan(0, 0, 0, 1, rndTimeOffset + 150) });
                    //Guns.Add(new BatGun(Game, this, "Textures/BatGun/BotRBasic", GunPos.Bottom) { rateOfFire = new TimeSpan(0, 0, 0, 1, rndTimeOffset) });
                    break;
                case PlayerIndex.Two:
                    //Color = Game1.Player2Color;
                    XClamp = 128 + Game1.ScreenMargin;
                    //Guns.Add(new BatGun(Game, this, "Textures/BatGun/TopLBasic", GunPos.Top) { rateOfFire = new TimeSpan(0, 0, 0, 1, rndTimeOffset + 50) });
                    //Guns.Add(new BatGun(Game, this, "Textures/BatGun/MidLBasic", GunPos.Center) { rateOfFire = new TimeSpan(0, 0, 0, 1, rndTimeOffset + 150) });
                    //Guns.Add(new BatGun(Game, this, "Textures/BatGun/BotLBasic", GunPos.Bottom) { rateOfFire = new TimeSpan(0, 0, 0, 1, rndTimeOffset) });
                    break;
            }

            Speed = 1;
            Friction = .05f;

            RegisteredCollider = true;            

        }

        public void MoveUp(float spd)
        {
            Velocity -= new Vector2(0, spd);
        }
        public void MoveDown(float spd)
        {
            Velocity += new Vector2(0, spd);
        }
        public override void Update(GameTime gameTime)
        {
            // Do movement
            switch (Player)
            {
                case PlayerIndex.One:
                    if (Game.IsKeyDown(Keys.Up))
                        MoveUp(Speed);

                    if (Game.IsKeyDown(Keys.Down))
                        MoveDown(Speed);

                    if(Game.thisP1GP.ThumbSticks.Left.Y < 0)
                        MoveDown(Speed);
                    if (Game.thisP1GP.ThumbSticks.Left.Y > 0)
                        MoveUp(Speed);

                    break;
                case PlayerIndex.Two:
                    if (Game.Players == 2)
                    {
                        if (Game.IsKeyDown(Keys.W))
                            MoveUp(Speed);

                        if (Game.IsKeyDown(Keys.S))
                            MoveDown(Speed);

                        if (Game.thisP2GP.ThumbSticks.Left.Y < 0)
                            MoveDown(Speed);
                        if (Game.thisP2GP.ThumbSticks.Left.Y > 0)
                            MoveUp(Speed);
                    }
                    else
                    {
                        // the AI takes over!
                        AIBlockBall();
                        switch (Game.Level)
                        {
                            case 0:
                            case 1:
                            case 2:
                                // get any Pickups.
                                AIGetGoodPickups();
                                break;
                            case 3:
                            case 4:
                                // Keep the ball out, shoot when infront of a players live city.
                                AIGetNearestPickup();
                                break;
                            case 5:
                            case 6:
                            case 7:
                                // Keep the ball out, hunt wounded cities..
                                break;
                            case 8:
                            case 9:
                            case 10:
                                break;
                            default:
                                break;
                        }
                    }
                    break;
            }

            base.Update(gameTime);

            Position = Vector2.Clamp(Position, minPosition, maxPosition);

            foreach (BatGun gun in Guns)
            {
                if (Game.Players == 1 && Player == PlayerIndex.Two)
                    gun.Shoot();
                else
                {
                    if (Player == PlayerIndex.One)
                    {
                        if ((Game.IsKeyDown(Keys.Right) || Game.IsP1RightTriggerPulled) && gun.gunPosition == GunPos.Top)
                            gun.Shoot();
                        if ((Game.IsKeyDown(Keys.Left) || Game.IsP1LeftTriggerPulled) && gun.gunPosition == GunPos.Bottom)
                            gun.Shoot();
                        if ((Game.IsKeyDown(Keys.Right) || Game.IsP1RightTriggerPulled) && (Game.IsKeyDown(Keys.Left) || Game.IsP1LeftTriggerPulled) && gun.gunPosition == GunPos.Center)
                            gun.Shoot();

                        
                    }

                    if (Player == PlayerIndex.Two)
                    {
                        if ((Game.IsKeyDown(Keys.E) || Game.IsP2RightTriggerPulled) && gun.gunPosition == GunPos.Top)
                            gun.Shoot();
                        if ((Game.IsKeyDown(Keys.Q) || Game.IsP2LeftTriggerPulled) && gun.gunPosition == GunPos.Bottom)
                            gun.Shoot();
                        if ((Game.IsKeyDown(Keys.E) || Game.IsP2RightTriggerPulled) && (Game.IsKeyDown(Keys.Q) || Game.IsP2LeftTriggerPulled) && gun.gunPosition == GunPos.Center)
                            gun.Shoot();
                    }
                }

                gun.Update(gameTime);
            }
        }

        void AIGetGoodPickups()
        {
            List<PickupType> bad = new List<PickupType>(new PickupType[]{
                PickupType.FlipH,
                PickupType.FlipV,
                PickupType.MinusBall,
                PickupType.Mist,
                PickupType.ScreenSpin,
            });
            //List<PickupType> good = new List<PickupType>(new PickupType[]{
            //    PickupType.Ammo,
            //    PickupType.CityRepair,
            //    PickupType.CityReserection,
            //    PickupType.Gun,
            //    PickupType.Heal,
            //    PickupType.LevelUp,
            //    PickupType.Shield,
            //    PickupType.MultiBall
            //});

            MoveToTarget(AIGetNearestPickup(bad));
        }

        Pickup AIGetNearestPickup(List<PickupType> excluding = null)
        {
            if(excluding == null)
                excluding = new List<PickupType>();

            List<Pickup> pl = Game.PickupsInPlay.Where(entity => excluding.Contains(entity.PickupTyp)).ToList();

            Pickup nearest = null;
            float pd = float.MaxValue;
            foreach (Pickup pickup in Game.PickupsInPlay)
            {
                float d = Vector2.Distance(pickup.Position, Position);
                if (d < pd)
                {
                    pd = d;
                    nearest = pickup;
                }
            }


            return nearest;
        }

        void AIBlockBall()
        {
            List<Ball> incommingBalls = Game.Balls.Where(ball => ball.Velocity.X < 0).ToList();

            Ball nearestBall = null;
            float bd = float.MaxValue;
            foreach (Ball ball in incommingBalls)
            {
                float d = Vector2.Distance(ball.Position, Position);
                if (d < bd)
                {
                    nearestBall = ball;
                    bd = d;
                }
            }

            MoveToTarget(nearestBall);
        }

        void MoveToTarget(Base2DObject obj)
        {
            float spMod = 1;

            if (Game.Level < 4)
                spMod = 3;

            if (Game.Level < 6)
                spMod = 2;

            if (obj != null)
            {
                if (Position.Y < obj.Position.Y)
                    MoveDown(Speed / spMod);

                if (Position.Y > obj.Position.Y)
                    MoveUp(Speed / spMod);
            }
        }

        public override void Collided(CollisionData collisionData)
        {
            base.Collided(collisionData);

            Base2DObject collidedWith = null;
            if (collisionData.Objects[0] == this)
                collidedWith = (Base2DObject)collisionData.Objects[1];
            else
                collidedWith = (Base2DObject)collisionData.Objects[0];

            if (collidedWith is Ball)
            {
                // Do somthing..
                Score += Game.Level * 100;
            }

            if (collidedWith is Bullet)
            {
                // Do something..
                Score -= Game.Level * 1;
                if (Score < 0)
                    Score = 0;
            }
        }

        public void WallHit()
        {
            //Score -= Game.Level * 10;

            //if (Score < 0)
            //    Score = 0;

            BatGun remG = null;
            foreach (BatGun gun in Guns)
            {
                gun.Ammo -= 25;
                if (gun.Ammo < 0)
                {
                    gun.Ammo = 0;
                    remG = gun;
                }
            }

            //if (remG != null)
            //    Guns.Remove(remG);
        }

        public override bool Erroded(Base2DObject obj, bool errodBat = false)
        {
            bool eroded = false;

            // remove pixels from the texture...
            int yRow = (int)MathHelper.Clamp(Math.Abs((Position.Y - halfHeight) - ((obj.Position.Y - obj.Height))), 0, Texture2D.Height - 1);

            if (yRow - obj.halfHeight >= 0)
                yRow -= obj.halfHeight;

            int tookOut = 0;

            for (int y = 0; y < obj.Height; y++)
            {
                if (Player == PlayerIndex.One)
                {
                    for (int x = 0; x < Texture2D.Width; x++)
                    {
                        if (TextureMap[x + yRow * Texture2D.Width].A != 0)
                        {
                            if (errodBat)
                            {
                                TextureMap[x + yRow * Texture2D.Width].A = 0;

                                for (int w = 1; w < obj.Height; w++)
                                {
                                    if (yRow - w > 0 && Game1.rnd.NextDouble() > .5)
                                        TextureMap[x + (yRow - w) * Texture2D.Width].A = 0;

                                    if (w + yRow < Texture2D.Height - 1 && Game1.rnd.NextDouble() > .5)
                                        TextureMap[x + (w + yRow) * Texture2D.Width].A = 0;
                                }
                            }
                            tookOut++;
                            eroded = true;

                            if (tookOut > obj.Width)
                                break;

                        }
                    }
                }
                else
                {
                    for (int x = Texture2D.Width - 1; x >= 0; x--)
                    {
                        if (TextureMap[x + yRow * Texture2D.Width].A != 0)
                        {
                            if (errodBat)
                            {
                                TextureMap[x + yRow * Texture2D.Width].A = 0;

                                for (int w = 1; w < obj.Height; w++)
                                {
                                    if (yRow - w > 0 && Game1.rnd.NextDouble() > .5)
                                        TextureMap[x + (yRow - w) * Texture2D.Width].A = 0;

                                    if (w + yRow < Texture2D.Height - 1 && Game1.rnd.NextDouble() > .5)
                                        TextureMap[x + (w + yRow) * Texture2D.Width].A = 0;
                                }
                            }

                            tookOut++;

                            eroded = true;

                            if (tookOut > obj.Width)
                                break;

                        }
                    }
                }

                yRow++;
                if (yRow >= Texture2D.Height)
                    yRow = Texture2D.Height - 1;
            }


            if (eroded && errodBat)
                Texture2D.SetData<Color>(TextureMap);

            return eroded;
        }

        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);

            foreach (BatGun gun in Guns)
                gun.Draw(gameTime);
        }

        public void DrawGunData()
        {
            Vector2 pos = new Vector2();
            

            string gunData = string.Empty;
            Vector2 posOffset = new Vector2(0, Game.Content.Load<SpriteFont>("Fonts/gundatafont").LineSpacing);
            Vector2 shadowOffset = new Vector2(-2, 2);
            int cnt = 0;

            foreach (BatGun gun in Guns)
            {
                gunData = string.Format("{0:0000} : {1}", gun.Ammo, gun.gunPosition);

                switch (Player)
                {
                    case PlayerIndex.One:
                        pos = new Vector2((Game1.RenderAreaCenter.X + (Game1.RenderArea.Width / 4)), 8);
                        break;
                    case PlayerIndex.Two:
                        pos = new Vector2((Game1.RenderAreaCenter.X - (Game1.RenderArea.Width / 4)), 8);
                        break;
                }

                Game.spriteBatch.DrawString(Game.Content.Load<SpriteFont>("Fonts/gundatafont"), gunData, (pos + shadowOffset + (posOffset * cnt)) , Color.Black);
                Game.spriteBatch.DrawString(Game.Content.Load<SpriteFont>("Fonts/gundatafont"), gunData, pos + (posOffset *cnt++), Color);
            }
        }
    }
}
